//
//  HYFileDownloadTask.m
//  VideoFileDownloadDemo
//
//  Created by liguoqing on 2023/8/25.
//

#import "HYFileDownloadTask.h"
#import <LKDBHelper/LKDBHelper.h>
#import "AFDownloadRequestOperation.h"
#import "HYBriefDownloadHelper.h"
#import "HYBriefDownloadConfig.h"

@interface HYFileDownloadTask ()
{
    AFDownloadRequestOperation *_downloadOperation;
    dispatch_source_t _timer;
}
/**
 *  上次文件接收总大小(字节)
 */
@property (nonatomic, assign) long long lastFileReceivedSize;

@end

@implementation HYFileDownloadTask

#pragma mark -开始下载
// 开始下载
- (void)start
{
    self.status = HYDownloadStatus_Downloading;
    self.fileCompletedTime = nil;
    [self saveToDB];
    [self startRequest];
}
// 开始下载请求
- (void)startRequest
{
    // 记录上次接受的文件大小
    self.lastFileReceivedSize = 0;
    
    // 创建存储和临时下载文件夹
    [HYBriefDownloadHelper checkAndCreateDirectoryAtPath:[self.filePath stringByDeletingLastPathComponent]];
    [HYBriefDownloadHelper checkAndCreateDirectoryAtPath:[self.tempFilePath stringByDeletingLastPathComponent]];
    
    // 设置文件权限
    [[NSFileManager defaultManager] setAttributes:[NSDictionary dictionaryWithObject:NSFileProtectionNone forKey:NSFileProtectionKey] ofItemAtPath:[HYBriefDownloadHelper documentDirectory] error:NULL];
    [[NSFileManager defaultManager] setAttributes:[NSDictionary dictionaryWithObject:NSFileProtectionNone forKey:NSFileProtectionKey] ofItemAtPath:self.filePath error:NULL];
    [[NSFileManager defaultManager] setAttributes:[NSDictionary dictionaryWithObject:NSFileProtectionNone forKey:NSFileProtectionKey] ofItemAtPath:self.tempFilePath error:NULL];
    NSLog(@"[下载] - ID:%@;下载地址:%@", self.downloadID, self.currentUrl);
    
    // 创建下载请求
    NSURL *url = [NSURL URLWithString:self.currentUrl];
    NSURLRequest *urlRequest = [[NSURLRequest alloc] initWithURL:url];
    _downloadOperation = [[AFDownloadRequestOperation alloc] initWithRequest:urlRequest tempPath:self.tempFilePath targetPath:self.filePath shouldResume:YES];
    _downloadOperation.deleteTempFileOnCancel = NO; // 取消后手动删除，见cancel方法
    _downloadOperation.shouldOverwrite = YES;       // 重新下载允许覆盖
    
    // 开启定时器细化下载进度
    [self runTimer];
    
    __weak __typeof(self) wself = self;
    // 下载进度变化回调
    [_downloadOperation setProgressiveDownloadProgressBlock:^(AFDownloadRequestOperation *operation, NSInteger bytesRead, long long totalBytesRead, long long totalBytesExpected, long long totalBytesReadForFile, long long totalBytesExpectedToReadForFile) {
        __strong __typeof(wself) sself = wself;
        
        sself.fileReceivedSize = totalBytesReadForFile;
        if (totalBytesExpectedToReadForFile>0 && !sself.fileSize) {
            sself.fileSize = totalBytesExpectedToReadForFile;
        }
    }];
    
    // 下载完成回调
    [_downloadOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
        __strong __typeof(wself) sself = wself;
        NSInteger statusCode = operation.response.statusCode;
        if (statusCode < 200 || statusCode > 299) {
            // 下载失败
            if (sself.failed) {
                NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:-1011 userInfo:nil];
                sself.failed(sself, error);
            }
            [sself stopTimer];
            // 下载失败自动取消下载任务
            [wself cancel];
            [sself downloadError];
        } else {
            // 下载成功
            sself.fileCompletedTime = [NSDate date]; // 记录下载完成的时间
            [sself saveToDB];
            
            NSLog(@"[下载] - 下载完成:%@", sself.filePath);
            
            [sself stopTimer];
            [sself complete];
        }
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        // 下载失败
        __strong __typeof(wself) sself = wself;
        
        NSLog(@"[下载] - 下载错误: %@, %@", sself.currentUrl, sself.filePath);
        
        [sself stopTimer];
        if (sself.failed) {
            sself.failed(sself, error);
        }
        // 下载失败自动取消下载任务
        [sself cancel];
        [sself downloadError];
    }];
    
    [self saveToDB];
    [_downloadOperation start];
}
// 开启定时器
- (void)runTimer
{
    uint64_t intervalInNanoSecs = (uint64_t)([HYBriefDownloadConfig sharedInstance].progressedReportInteval * NSEC_PER_MSEC);
    uint64_t leewayInNanoSecs = (uint64_t)(500 * NSEC_PER_MSEC);
    
    _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
    dispatch_source_set_timer(_timer, dispatch_walltime(NULL, 0), intervalInNanoSecs,
                              leewayInNanoSecs);
    
    __weak __typeof(self) wself = self;
    dispatch_source_set_event_handler(_timer, ^{
        __strong __typeof(wself) sself = wself;
        if (sself.status == HYDownloadStatus_Downloading) {
            
            // 只有当接收文件大小变化是才通知进度变更
            if (sself.fileReceivedSize != sself.lastFileReceivedSize) {
                sself.lastFileReceivedSize = sself.fileReceivedSize;
                
                NSLog(@"[下载] - [%@]-进度:%.2f%%, %lld, %lld", sself.downloadID, sself.fileReceivedSize * 100. / sself.fileSize, sself.fileReceivedSize, sself.fileSize);
                // 代理和block方式均通知
                if (sself.delegate && [sself.delegate respondsToSelector:@selector(progressChangedWithBytesReceived:totalBytes:)]) {
                    [sself.delegate progressChangedWithBytesReceived:sself.fileReceivedSize totalBytes:sself.fileSize];
                }
                if (sself.progressChanged) {
                    sself.progressChanged(sself, sself.fileReceivedSize, sself.fileSize);
                }
            }
        }
    });
    dispatch_resume(_timer);
}
// 停止定时器
- (void)stopTimer
{
    self.lastFileReceivedSize = 0;
    
    if (_timer) {
        dispatch_source_cancel(_timer);
        
        // 代理和block方式均通知
        if (self.delegate && [self.delegate respondsToSelector:@selector(progressChangedWithBytesReceived:totalBytes:)]) {
            [self.delegate progressChangedWithBytesReceived:self.fileReceivedSize totalBytes:self.fileSize];
        }
        if (self.progressChanged) {
            self.progressChanged(self, self.fileReceivedSize, self.fileSize);
        }
        
        _timer = nil;
    }
}

#pragma mark -删除下载任务
- (void)cancel
{
    [self stopTimer];
    [_downloadOperation cancel];
    [self deleteToDB];
    [self clearDownloadData];
    self.status = HYDownloadStatus_Default;
}

- (void)pause
{
    if(self.status != HYDownloadStatus_Pause){
        [self stopTimer];
        [_downloadOperation pause];
        self.status = HYDownloadStatus_Pause;
        [self saveToDB];
    }
}

// 清除临时文件
- (void)clearDownloadData
{
    NSFileManager *fileManager = [NSFileManager new];
    BOOL fileExists = [fileManager fileExistsAtPath:self.filePath];
    if (fileExists)
    {
        [fileManager removeItemAtPath:self.filePath error:nil];
    }
    
    BOOL tempFileExists = [fileManager fileExistsAtPath:self.tempFilePath];
    if (tempFileExists)
    {
        [fileManager removeItemAtPath:self.tempFilePath error:nil];
    }
}

// 校验下载状态
- (void)checkStatus
{
    NSFileManager *fileManager = [NSFileManager defaultManager];
    
    // 下载路径文件是否存在
    BOOL saveFileExist = [fileManager fileExistsAtPath:self.filePath];
    if (saveFileExist) {
        self.status = HYDownloadStatus_Completed;
    }
}

- (void)startWaiting
{
    self.status = HYDownloadStatus_Waiting;
    [self saveToDB];
}

- (void)startResume
{
    self.status = HYDownloadStatus_Waiting;
}

- (void)downloadError
{
    self.status = HYDownloadStatus_Error;
    [self saveToDB];
}

+ (void)clearAllDownloadData
{
    [self deleteWithWhere:@"1"];
}

@end
